﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace A14_Ex06_Noam_300476694_Shai_300380698
{
    public class BoardForm : Form
    {
        #region Messages

        public const string k_EnterWidth = "Please enter the width of the board (minimum {0}, maximum {1})";
        public const string k_EnterHeight = "Please enter the height of the board (minimum {0}, maximum {1})";
        public const string k_DeclareWinner = "{0} Won!!";
        public const string k_DeclareTie = "Tie!!";
        public const string k_Rematch = "Another Round?";

        #endregion

        #region Consts

        private const int k_BoardButtonSize = 35;
        private const int k_TitleButtonSize = 20;
        private const int k_BoardStartHeightPixel = 20;
        private const int k_BoardStartWidthPixel = 18;
        private const int k_WidthBetweenButtons = 10;
        private const int k_HeightBetweenButtons = 10;
        private const string k_computerDefaultName = "[Computer]";
        private const string k_computerGameName = "Computer";

        #endregion

        #region Data Members

        private GameSettings m_GameSettings;
        private GameLogic m_GameLogic;

        private Label labelPlayer1;
        private Label labelPlayer2;
        private Label labelPlayer1Score;
        private Label labelPlayer2Score;

        private List<Button> m_TitleButtons;
        private BoardButton[,] m_BoardButtons;

        #endregion

        public BoardForm()
        {
            m_GameLogic = new GameLogic();
            m_GameSettings = new GameSettings();

            if (m_GameSettings.ShowDialog() == DialogResult.OK)
            {
                m_BoardButtons = new BoardButton[m_GameSettings.Cols, m_GameSettings.Rows];
                m_TitleButtons = new List<Button>((int)m_GameSettings.Cols);

                StartNewGame();
                InitializeComponent();

                this.ShowDialog();
            }
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();

            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
            this.Name = "BoardForm";
            this.Text = "4 In a Row";
            this.StartPosition = FormStartPosition.CenterScreen;
            this.FormBorderStyle = FormBorderStyle.FixedToolWindow;
            this.AutoSize = true;
            this.ClientSize = new System.Drawing.Size(((int)m_GameSettings.Cols * 46) + 20, (int)m_GameSettings.Rows * 60);
            this.ResumeLayout(false);

            initLabels();
        }

        private void initLabels()
        {
            labelPlayer1 = new Label();
            labelPlayer2 = new Label();
            labelPlayer1Score = new Label();
            labelPlayer2Score = new Label();

            labelPlayer1.AutoSize = true;
            labelPlayer1.Location = new System.Drawing.Point(((this.Location.X + this.ClientSize.Width) / 2) - 60, this.ClientSize.Height - 5);
            labelPlayer1.Visible = true;
            labelPlayer1.Text = m_GameSettings.Player1;

            labelPlayer1Score.AutoSize = true;
            labelPlayer1Score.Location = new System.Drawing.Point(labelPlayer1.Left + 50, this.ClientSize.Height - 5);
            labelPlayer1Score.Visible = true;
            labelPlayer1Score.Text = "0";

            labelPlayer2.AutoSize = true;
            labelPlayer2.Location = new System.Drawing.Point(labelPlayer1Score.Left + 30, this.ClientSize.Height - 5);
            labelPlayer2.Visible = true;
            labelPlayer2.Text = m_GameSettings.Player2 == k_computerDefaultName ? k_computerGameName : m_GameSettings.Player2;

            labelPlayer2Score.AutoSize = true;
            labelPlayer2Score.Location = new System.Drawing.Point(labelPlayer2.Left + 60, this.ClientSize.Height - 5);
            labelPlayer2Score.Visible = true;
            labelPlayer2Score.Text = "0";

            this.Controls.AddRange(new Control[] { this.labelPlayer1, this.labelPlayer2, this.labelPlayer1Score, this.labelPlayer2Score });
        }

        private void StartNewGame()
        {
            initBoard();
            initPlayer2();
        }

        private void initBoard()
        {
            if (m_GameLogic.Board == null)
            {
                m_GameLogic.Board = new Board(m_GameSettings.Cols, m_GameSettings.Rows);
            }

            m_GameLogic.InitBoard();

            if (m_TitleButtons.Count > 0)
            {
                clearTitleButtons();
            }
            else
            {
                initTitleButtons();
            }

            if (m_BoardButtons[0, 0] == null)
            {
                initBoardButtons();
            }

            m_GameLogic.ResetCurrentPlayer();
        }

        private void initTitleButtons()
        {
            if (m_TitleButtons.Count == 0)
            {
                int PreviousLocationHeight = k_BoardStartHeightPixel;
                int PreviousLocationWidth = k_BoardStartWidthPixel;

                for (int i = 0; i < m_GameSettings.Cols; i++)
                {
                    m_TitleButtons.Add(new Button());
                    m_TitleButtons[i].Text = (i + 1).ToString();
                    m_TitleButtons[i].Location = new System.Drawing.Point(PreviousLocationWidth, PreviousLocationHeight);
                    m_TitleButtons[i].Size = new System.Drawing.Size(k_BoardButtonSize, k_TitleButtonSize);
                    m_TitleButtons[i].Enabled = true;
                    this.Controls.Add(m_TitleButtons[i]);
                    this.m_TitleButtons[i].Click += new EventHandler(ButtonTitle_Click);
                    PreviousLocationWidth += k_BoardButtonSize + k_WidthBetweenButtons;
                }
            } 
        }

        private void clearTitleButtons()
        {
            for (int i = 0; i < m_GameSettings.Cols; i++)
            {
                m_TitleButtons[i].Enabled = true;
            }
        }

        private void initBoardButtons()
        {
            int PreviousLocationHeight = k_BoardStartHeightPixel + k_TitleButtonSize + k_HeightBetweenButtons;
            int PreviousLocationWidth = k_BoardStartWidthPixel;

            Cell[,] cellsOnBoard = m_GameLogic.GetBoardCellsMat();

            for (int i = 0; i < m_GameSettings.Cols; i++)
            {
                for (int j = 0; j < m_GameSettings.Rows; j++)
                {
                    m_BoardButtons[i, j] = new BoardButton();
                    m_BoardButtons[i, j].Location = new System.Drawing.Point(PreviousLocationWidth, PreviousLocationHeight);
                    m_BoardButtons[i, j].Size = new System.Drawing.Size(k_BoardButtonSize, k_BoardButtonSize);
                    m_BoardButtons[i, j].Text = string.Empty;

                    cellsOnBoard[i, j].m_onChangeDelegate += m_BoardButtons[i, j].onButtonInsert;
                    this.Controls.Add(m_BoardButtons[i, j]);

                    PreviousLocationHeight += k_BoardButtonSize + k_HeightBetweenButtons;
                }

                PreviousLocationWidth += k_BoardButtonSize + k_WidthBetweenButtons;
                PreviousLocationHeight = k_BoardStartHeightPixel + k_TitleButtonSize + k_HeightBetweenButtons;
            }
        }

        private void initPlayer2()
        {
            m_GameLogic.Player2 = new Player(m_GameSettings.PlayerType, 2);
        }

        private string getPlayerNameByNumber(uint i_PlayerNumber)
        {
            string result = string.Empty;

            if (i_PlayerNumber == 1)
            {
                result = m_GameSettings.Player1;
            }
            else if (i_PlayerNumber == 2)
            {
                result = m_GameSettings.Player2;
            }
            else
            {
                result = string.Empty;
            }

            return result;
        }

        private string getPlayerSymbolByNumber(uint i_PlayerNumber)
        {
            string result = string.Empty;

            if (i_PlayerNumber == 1)
            {
                result = ePlayerSymbol.X.ToString();
            }
            else if (i_PlayerNumber == 2)
            {
                result = ePlayerSymbol.O.ToString();
            }
            else
            {
                result = string.Empty;
            }

            return result;
        }

        private void endGame()
        {
            this.Close();
        }

        private void showMessageBoxWithOK(string i_Message)
        {
            MessageBox.Show(i_Message, "Message", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private bool showMessageBoxWithYesNo(string i_Message)
        {
            bool result = false;

            if (MessageBox.Show(i_Message, "Message", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == System.Windows.Forms.DialogResult.Yes)
            {
                result = true;
            }
            else
            {
                result = false;
            }

            return result;
        }

        private void ButtonTitle_Click(object sender, EventArgs e)
        {
            base.OnClick(e);

            uint column = 0;
            bool k_HumanPlayer = true;
            bool gameOver = false;

            Button clickedTitleButton = sender as Button;
            bool goodInput = uint.TryParse(clickedTitleButton.Text, out column);

            if (m_GameSettings.PlayerType == ePlayerType.Computer)
            {
                gameOver = makeTurn(k_HumanPlayer, column);
                if (!gameOver)
                {
                    m_GameLogic.ChangeCurrentPlayer();
                }

                gameOver = makeTurn(!k_HumanPlayer, null);
                if (!gameOver)
                {
                    m_GameLogic.ChangeCurrentPlayer();
                }
            }
            else
            {
                gameOver = makeTurn(k_HumanPlayer, column);
                if (!gameOver)
                {
                    m_GameLogic.ChangeCurrentPlayer();
                }
            }
        }

        private bool makeTurn(bool i_Human, uint? i_PickedColumn)
        {
            uint? pickedRow = null;
            const bool MatchEndedWithTie = true;
            string errorMessage = string.Empty;
            bool successMove = false;
            bool playerWonAfterTurn = false;
            bool gameOver = false;

            if (i_Human)
            {
                if (i_PickedColumn != null)
                {
                    pickedRow = m_GameLogic.FindRowInAvailableMovesByColumn((uint)i_PickedColumn);
                }
            }
            else
            {
                m_GameLogic.MakeAutomaticMove(m_GameLogic.CurrentPlayer, out i_PickedColumn, out pickedRow);
            }

            if (pickedRow != null)
            {
                successMove = m_GameLogic.SetSquareOnBoard(m_GameLogic.CurrentPlayer, (uint)i_PickedColumn, (uint)pickedRow, out errorMessage);
                if (successMove)
                {
                    disableColumnIfColumnIsFull((int)i_PickedColumn);

                    playerWonAfterTurn = m_GameLogic.CheckIfCurrentPlayerWon((uint)i_PickedColumn, (uint)pickedRow);
                    if (playerWonAfterTurn)
                    {
                        matchIsOver(!MatchEndedWithTie);
                        gameOver = true;
                    }

                    if (m_GameLogic.IsBoardFull())
                    {
                        matchIsOver(MatchEndedWithTie);
                        gameOver = true;
                    }
                }
            }
            else
            {
                errorMessage = Board.k_ErrorIllegalMove;
                successMove = false;
            }

            if (!successMove)
            {
                if (errorMessage != string.Empty)
                {
                    showMessageBoxWithOK(errorMessage);
                }
            }

            return gameOver;
        }

        private void matchIsOver(bool i_Tie)
        {
            bool playerWon = false;

            if (i_Tie)
            {
                playerWon = false;
            }
            else
            {
                m_GameLogic.CurrentPlayer.RaisePlayerScore();
                labelPlayer1Score.Text = m_GameLogic.Player1.Score.ToString();
                labelPlayer2Score.Text = m_GameLogic.Player2.Score.ToString();
                playerWon = true;
            }

            askForRematch(playerWon);
        }

        private void askForRematch(bool i_PlayerWon)
        {
            string message = string.Empty;

            if (i_PlayerWon == true)
            {
                string winner = string.Format(k_DeclareWinner, getPlayerNameByNumber(m_GameLogic.CurrentPlayerNumber));
                message = string.Format("{0}{1}{2}", winner, System.Environment.NewLine, k_Rematch);
            }
            else
            {
                message = string.Format("{0}{1}{2}", k_DeclareTie, System.Environment.NewLine, k_Rematch);
            }

            m_GameLogic.ChangeCurrentPlayer();
            bool rematch = showMessageBoxWithYesNo(message);

            if (rematch)
            {
                initBoard();
            }
            else
            {
                endGame();
            }
        }

        private void disableColumnIfColumnIsFull(int i_ColumnToCheck)
        {
            if (m_GameLogic.IsColumnFull(i_ColumnToCheck))
            {
                m_TitleButtons[i_ColumnToCheck - 1].Enabled = false;
            }
        }

        #region Designer Methods
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }

            base.Dispose(disposing);
        }
        #endregion
    }
}
